/*
 * RealTests.h
 *
 */
#ifndef _REAL_TESTS_H_
#define _REAL_TESTS_H_

#include <cppunit/TestCase.h>
#include <cppunit/TestSuite.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestAssert.h>

#include "Real.h"

class RealTests : public CppUnit::TestFixture
{
	CPPUNIT_TEST_SUITE(RealTests);
	CPPUNIT_TEST(testSetPrecision);
	CPPUNIT_TEST(testTruncationDoesNotAffectValue);
	CPPUNIT_TEST(testTruncationDoesAffectValue);
	CPPUNIT_TEST(testAddition);
	CPPUNIT_TEST(testSubtraction);
	CPPUNIT_TEST(testProduct);
	CPPUNIT_TEST(testDivision);
	CPPUNIT_TEST(testDoubleMultipliedByReal);
	CPPUNIT_TEST(testDoubleDividedByReal);
	CPPUNIT_TEST_SUITE_END();

public:

	void setUp() {
		// Double		-> 		Real precision == 16
		//  5.12345 		-> 		 5.1234130859375
		// 26.249145508		->		26.2490234375
		// 26.249361649 	-> 		26.249267578125
		// 31.372680664		->		31.37255859375

		Real::precision(16);
	}

	void tearDown() { }

	void testSetPrecision() {
		const unsigned int NEW_PRECISION(24);

		Real::precision(NEW_PRECISION);

		CPPUNIT_ASSERT_EQUAL(NEW_PRECISION, Real::precision());
	}

	void testTruncationDoesNotAffectValue() {
		const double EXPECTED_VALUE(-118.625);

		Real aReal(-118.625);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, aReal.value(), 0.0001);
	}

	void testTruncationDoesAffectValue() {
		const double EXPECTED_VALUE(-118.5);
		const unsigned int NEW_PRECISION(8);

		Real::precision(NEW_PRECISION);

		Real aReal(-118.625);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, aReal.value(), 0.001);
	}

	void testAddition() {
		const double EXPECTED_VALUE(31.37255859375);

		Real aReal(5.12345);
		Real anotherReal(26.249361649);
		Real result(aReal + anotherReal);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, result.value(), 0.00000000001);
	}

	void testSubtraction() {
		const double EXPECTED_VALUE(26.2490234375);

		Real aReal(5.12345);
		Real anotherReal(31.372680664);
		Real result(anotherReal - aReal);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, result.value(), 0.00000000001);
	}

	void testProduct() {
		const double EXPECTED_VALUE(26.249267578125);

		Real aReal(5.12345);
		Real aRealSquared(aReal * aReal);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, aRealSquared.value(), 0.00000000001);
	}

	void testDivision() {
		const double EXPECTED_VALUE(6.12335205078125);

		Real aReal(5.12345);
		Real anotherReal(31.372680664);
		Real result(anotherReal / aReal);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, result.value(), 0.00000000001);
	}

	void testDoubleMultipliedByReal() {
		const double EXPECTED_VALUE(31.372314453125);

		Real aReal(6.12335205078125);
		Real result(5.12345 * aReal);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, result.value(), 0.00000000001);
	}

	void testDoubleDividedByReal() {
		const double EXPECTED_VALUE(6.12335205078125);

		Real aReal(5.12345);
		Real result(31.372680664 / aReal);

		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, result.value(), 0.00000000001);
	}

	void testAssignIsSameAsConstruction(){
		const double EXPECTED_VALUE(6.12335205078125);
		Real a(EXPECTED_VALUE);
		Real b;
		b = EXPECTED_VALUE;
		Real c;
		c = b;
		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, a.value(), 0.00001);
		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, b.value(), 0.00001);
		CPPUNIT_ASSERT_DOUBLES_EQUAL(EXPECTED_VALUE, c.value(), 0.00001);
	}
};

#endif /* _REAL_TESTS_H_ */
